/***************************************************
 ** Create by Hasaki on 2021/11/19.
 ** This file is part of the CSTL project.
 ** This file follows version 3 of GNU License.
 ** About GNU, see <https://www.gnu.org/licenses/>.
 **
 ** 本文件由Hasaki(间宫羽咲sama)于2021年11月19日创建。
 ** 本文件是CSTL(C-STL)项目的一部分。
 ** 本文件遵从GNU-v3协议。
 ** 关于GNU协议，见<https://www.gnu.org/licenses/>。
 ***************************************************/
#ifndef HASAKI_VECTOR_H
#define HASAKI_VECTOR_H   // HskVector.h

#include <stdio.h>
#include <malloc.h>
#include <string.h>       // To include memcpy
#include <stdint.h>       // To include size_t, uint_8
#include "HskUtil.h"

/** -- final editor: Hasaki at 2021/11/25
 * @brief Vector类
 * 本类储存Vector类的数据成员和操作函数集合_obj
 * 不建议存指针，而是存类本身，因为析构函数不会free掉指针指向的对象
 */
typedef struct _Vector {
  // data，可看作void []，要求begin<=end<=last
  void  *_begin;  // begin指针，指向使用空间的头
  void  *_end;    // end指针，指向使用空间的尾
  void  *_last;   // 指向分配空间的尾
  size_t _tsize;
} Vector;

/** -- final editor: Hasaki at 2021/11/27
 * 我们约定typesize代表sizeof(type)，_type代表容器里存的数据类型
 * _this代表被操作对象的this指针，size代表已用空间，capa代表最大容量
 * Vector类相关的接口函数如下——
 * VecCreate(typesize, size, capa);       // Vector的构造函数
 * VecClean(_this);                       // Vector的析构函数
 * VecDelete(_pthis);                     // Vector的析构函数，析构后将Vec指针置为NULL
 * VecReCapa(_this, newCapa);             // 将Vector的最大容量capa重置为newCapa，会分配一段新的空间
 * VecReSize(_this, newSize);             // 将Vector的已用空间size重置为newSize，如果newSize <= capa，不会分配新的空间
 * VecHandleAll(_this, handle);           // 对于Vector内的元素都执行函数handle
 * VecPush(_this, elem);                  // 往Vector的end处push back一个elem指向的内容
 * VecPushSlice(_this, elemBeg, elemEnd); // 往Vector的end处push back一个[elemBeg, elemEnd)的内容
 * VecDelN(_this, _N);                    // 将Vector的[size - N, size)的元素置0，并size减少N
 * VecGet(_this, _N);                     // 返回Vector的vec->begin + vec->tsize*N
 * VecGetSize(_this);                     // 返回Vector的已用空间
 * BufGetCapa(_this);                     // 返回Vector的容量
 * BufDispMsg(_this);                     // 显示自己的size, capacity, typesize
 */

/** -- final editor: Hasaki at 2021/11/25
 * @brief   VecCreate构造函数
 * @details 构造装有size个typesize大的Vector类，初值为0
 *          初始空间分配capacity*typesize（要求size <= capacity）
 * @note    伪代码如下：
 *          std::vector<type> vec;
 *          vec.resize(size);
 *          vec.reserve(capacity);
 *          return &vec;
 * @param[in] typesize: 相当于sizeof(type)
 * @param[in] size    : 初始创建的个数size，应小于等于capacity
 * @param[in] capacity: 初始预分配的容量数capacity
 * @retval  指向被创建的结构体的指针
 * @code
 *  // 创建装有24个类型为int的Vector类，保留空间为42*sizeof(int)
 *  Vector *vec = VecCreate(sizeof(int), 24, 42);
 * @endcode
 */
Vector* VecCreate(const size_t typesize, const size_t size, size_t capacity);

/** -- final editor: Hasaki at 2021/11/26
 * @brief   VecClean析构函数
 * @details 清理vec对应的资源和vec->begin
 * @code
 *  // 清理vec指向的资源，执行完记住把Vector *置为NULL
 *  Vector *vec1 = VecCreate(sizeof(int), 24, 42);
 *  VecClean(vec1);
 *  vec1 = NULL;
 *  // 清理vec指向的资源，执行完vec2就被free掉了，不应再使用
 *  Vector vec2 = *VecCreate(sizeof(int), 24, 42);
 *  VecClean(&vec2);
 * @endcode
 */
void VecClean(Vector *_this);

/** -- final editor: Hasaki at 2021/11/29
 * @brief   VecDelete析构函数，析构后将Vec指针置为NULL
 * @details 相当于执行VecDelete再将自己置NULL
 * @code
 *  Vector *vec1 = VecCreate(sizeof(int), 24, 42);
 *  // 第一种清理方式
 *  VecDelete(&vec1);
 *  // 这等价于第一种清理方式
 *  VecClean(vec1);
 *  vec1 = NULL;
 * @endcode
 */
void VecDelete(Vector **_pthis);

/** -- final editor: Hasaki at 2021/11/26
 * @brief   将capacity扩容/缩减到指定的newCapa大小
 * @warning 一定会重新分配空间
 *          如果newCapa < size，则删掉this[newCapa:size]
 * @param[in] newCapa: 强制转化为的新容量
 * @note    伪代码如下：
 *          vec.reserve(newCapa);
 */
void VecReCapa(Vector *const _this, const size_t newCapa);

/** -- final editor: Hasaki at 2021/11/26
 * @brief   将size扩容/缩减到指定的newSize大小
 * @warning 如果newSize < size，则删掉this[newSize:size]
 * @param[in] newSize: 强制转化为的新长度
 * @note    伪代码如下：
 *          vec.resize(newSize);
 */
void VecReSize(Vector *const _this, const size_t newSize);

/** -- final editor: Hasaki at 2021/11/26
 * @brief   用handle对vec里的每一个元素进行操作
 * @details 因为传的是函数指针，不如内联优化效率高，建议手动展开
 * @warning 严禁handle对this的size或者capa进行任何修改！！！
 * @note    伪代码如下：
 *          seq = 0;
 *          for (auto *it : vec)
 *              handle(vec, it, seq ++);
 * @param[in] handle: 对于每一个元素进行遍历操作
 * @code
 *  // 注：这种仿lambda函数的方式仅在gcc编译器下可行，不然还是老老实实地在函数外定义吧
 *  // 例1：定义lambda函数PrintLongLongFun，对vec内的所有元素进行输出
 *  void PrintLongLongFun (Vector *const _this, void *data, size_t seq) {
 *    printf("%zu: %lld\n", seq, *(long long *)data);
 *  }
 *  VecHandleAll(vec, PrintLongLongFun);  // 用lambda函数处理vec
 *  // 例2：定义lambda函数LongLongFoo1，将data[n]赋值为7*n
 *  void LongLongFoo1 (Vector *const _this, void *data, size_t seq) {
 *    *(long long *)data = seq * 7;
 *  }
 *  VecHandleAll(vec1, LongLongFoo1);
 * @endcode
 */
void VecHandleAll(Vector *const _this, void (*handle)(Vector *const, void *, size_t));

/** -- final editor: Hasaki at 2021/11/27
 * @brief   往this->end处push一个*elem
 * @param[in] elem: 指向要push进去的元素指针
 * @code
 *  // 例：往vec里push一个1
 *  long long elem = 1;
 *  VecPush(vec, &elem);
 * @endcode
 */
void VecPush(Vector *const _this, const void *elem);

/** -- final editor: Hasaki at 2021/11/27
 * @brief   往this->end处push一个[elemBeg:elemEnd]切片
 * @param[in] elemBeg: 指向要push进去的elem的头指针
 * @param[in] elemEnd: 指向要push进去的elem的尾指针
 * @code
 *  // 例：往vec2里push一个vec1
 *  Vector *vec1, *vec2;
 *  VecPushSlice(vec2, vec1->_begin, vec1->_end);
 * @endcode
 */
void VecPushSlice(Vector *const _this, const void *elemBeg, const void *elemEnd);

/** -- final editor: Hasaki at 2021/11/27
 * @brief   删掉end末尾N个元素（置0）
 * @param[in] N: 删掉末尾N个元素
 * @code
 *  // 例：删除vec末尾5个元素
 *  VecDelN(vec, 5);
 * @endcode
 */
void VecDelN(Vector *const _this, const size_t _N);

/** -- final editor: Hasaki at 2021/11/29
 * @brief   返回void *类型指向(buf->_begin)[N]的指针
 * @retval  返回vec->begin的第N个元素
 * @code
 *  // 例1：以long long形式获取vec第2个元素
 *  printf("vec1[2] = %lld\n", *(long long*)VecGet(vec1, 2));
 *  // 例2：以long long形式将vec第2个元素置为100
 *  *(long long*)VecGet(vec1, 2) = 100;
 * @endcode
 */
void* VecGet(const Vector *const _this, const size_t N);

/** -- final editor: Hasaki at 2021/11/26
 * @brief   获取Vec的size = (end - begin) / typesize
 * @retval  返回vec的已用空间size
 */
size_t VecGetSize(const Vector *const _this);

/** -- final editor: Hasaki at 2021/11/26
 * @brief   获取Vec的capacity = (last - begin) / typesize
 * @retval  返回vec的最大容量capacity
 */
size_t VecGetCapa(const Vector *const _this);

/** -- final editor: Hasaki at 2021/11/26
 * @brief   显示自己的size, capacity, typesize
 */
void VecDispMsg(const Vector *const _this);

#endif  // HskVector.h
